package com.zx.tfw.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;
import com.zx.tfw.dao.TechnicalFrameworkDao;
import com.zx.tfw.dao.TechnicalManufacturerDao;
import com.zx.tfw.entity.TechnicalFramework;
import com.zx.tfw.entity.TechnicalFrameworkDto;
import com.zx.tfw.entity.TechnicalManufacturer;
import com.zx.tfw.entity.TfwStatisticsModel;
import com.zx.tfw.entity.TfyCountryModel;
import com.zx.tfw.entity.TfyTypeModel;
import com.zx.tfw.entity.TfyManufacturerModel;
import com.zx.tfw.entity.TfySkilledModel;
import com.zx.tfw.entity.tfwByTypeCodeDto;
import com.zx.tfw.enums.CountryEnum;
import com.zx.tfw.enums.LanguageEnum;
import com.zx.tfw.enums.LicenseEnum;
import com.zx.tfw.enums.OSEnum;
import com.zx.tfw.enums.SkilledEnum;
import com.zx.tfw.enums.TagEnum;
import com.zx.tfw.enums.TypeEnum;


@Service
public class TechnicalFrameworkService {
	
	private final static Logger LOGGER = LoggerFactory.getLogger(TechnicalFrameworkService.class);
	
	@Autowired
	private TechnicalFrameworkDao technicalFrameworkDao;
	
	@Autowired
	private TechnicalManufacturerDao technicalManufacturerDao;

	public List<TechnicalFramework> findAll() {
		return this.technicalFrameworkDao.findAll();
	}
	
	public void save(TechnicalFramework tfw) {
		this.technicalFrameworkDao.save(tfw);
	}

	public TechnicalFramework findById(Integer id) {
		Optional<TechnicalFramework> findById = this.technicalFrameworkDao.findById(id);
		return findById.orElse(null);
	}
	
	public TechnicalFrameworkDto findDtoById(Integer id) {
		TechnicalFramework data = this.findById(id);
		TechnicalFrameworkDto dto = new TechnicalFrameworkDto();
		if(data != null) {
			BeanUtils.copyProperties(data, dto);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			
			// 格式化时间
			dto.setBeginTimeStr(data.getBeginTime() == null ? "" : sdf.format(data.getBeginTime()));
			dto.setLastUpdateTimeStr(data.getLastUpdateTime() == null ? "" : sdf.format(data.getLastUpdateTime()));
			
			dto.setOsCodeStr(OSEnum.asMap().get(data.getOsCode()).getName());
			dto.setLicenseCodeStr(LicenseEnum.asMap().get(data.getLicenseCode()).getName());
			dto.setLanguageCodeStr(LanguageEnum.asMap().get(data.getLanguageCode()).getName());
			dto.setTagsCodeStr(TagEnum.asMap().get(data.getTagsCode()).getName());
			
			TechnicalManufacturer orElse = this.technicalManufacturerDao.findById(dto.getManufacturerCode()).orElse(new TechnicalManufacturer());
			dto.setManufacturerCodeStr(orElse.getmName());
			
			dto.setTypeCodeStr(TypeEnum.asMap().get(data.getTypeCode()).getName());
			dto.setSkilledCodeStr(SkilledEnum.asMap().get(data.getSkilledCode()).getName());
			dto.setSkilledColor(SkilledEnum.asMap().get(data.getSkilledCode()).getBackgroundColor());
			dto.setCountryCodeStr(CountryEnum.asMap().get(data.getCountryCode()).getName());
			
			// 切割网址
			dto.setSourcesUrlArr(StringUtils.isEmpty(data.getSourcesUrl()) ? new String[0] : data.getSourcesUrl().split(","));
			dto.setUccnUrlArr(StringUtils.isEmpty(data.getUccnUrl()) ? new String[0] : data.getUccnUrl().split(","));
			dto.setForumUrlArr(StringUtils.isEmpty(data.getForumUrl()) ? new String[0] : data.getForumUrl().split(","));
			
		}
		
		return dto;
	}
	
	/**
	 * @title 分组统计数据--按照技术类型分组{返回的数据是个table， 单行最多10个元素(加上头行有11个元素)}
	 * @return
	 * @author: xue.zhang
	 * @date 2019年1月31日下午2:29:13
	 */
	public List<TfyTypeModel> classificationByType() {
		int lineNum = 10;
		List<TechnicalFramework> all = this.technicalFrameworkDao.findAll();
		Map<Integer, List<TechnicalFramework>> collect = all.stream().collect(Collectors.groupingBy(TechnicalFramework::getTypeCode));
		List<TfyTypeModel> result = new ArrayList<>();
		for (TypeEnum typeEnum : TypeEnum.values()) {
			int typeCode = typeEnum.getCode();
			if(collect.containsKey(typeCode)) {
				List<TechnicalFramework> list = collect.get(typeCode);
				Lists.partition(list, lineNum).stream().forEach(x -> {
					List<tfwByTypeCodeDto> typeData = x.stream().map(ele -> new tfwByTypeCodeDto(ele)).collect(Collectors.toList());
					result.add(new TfyTypeModel(typeEnum, typeData));
				});
			} else {
				result.add(new TfyTypeModel(typeEnum, new ArrayList<>()));
			}
		}
		// 填充字段。保证每行有lineNum个元素
		for (TfyTypeModel ts : result) {
			LOGGER.debug("填充信息={}", ts);
			int size = ts.getTfws().size();
			int fullSize = lineNum - size;//需要填充几个
			for (int i = 0; i < fullSize; i++) {
				ts.getTfws().add(new tfwByTypeCodeDto());
			}
		}
		return result;
	}
	
	//############################### 以下方法为分类排序器 ##############################################//
	/**
	 * @title 分类排序器(高级方法)
	 * @param classifier	分组器【必传】。为数据分组提供依据。	类型为  R
	 * @param keyConverter	排序器【必传】，字段真实的类型 K	
	 * @param templateData	模板数据【必传】，作为返回数据的基准，将查询到的结果保存在fullData中	
	 * @return
	 * @author: xue.zhang
	 * @param <K>
	 * @date 2019年2月2日上午9:45:33
	 */
	public <R, K> List<TfwStatisticsModel<K, TechnicalFramework>> handler(
			Function<TechnicalFramework, R> classifier, 
			Function<R, K> keyConverter,
			List<TfwStatisticsModel<K, TechnicalFramework>> templateData
			) {
		if(CollectionUtils.isEmpty(templateData)) {
			return null;
		}
		// 查询数据
		List<TfwStatisticsModel<K, TechnicalFramework>> queryData = this.handler(classifier, null, keyConverter);
		Map<K, List<TechnicalFramework>> tempData = queryData.stream().collect(Collectors.toMap(TfwStatisticsModel::getKey, TfwStatisticsModel::getData));
		
		for (TfwStatisticsModel<K, TechnicalFramework> data : templateData) {
			K key = data.getKey();
			if(tempData.containsKey(key)) {
				data.setData(tempData.get(key));
				tempData.remove(key);//找到就移除数据
			}
		}
		if(!tempData.isEmpty()) {
			LOGGER.warn("有模板数据中不存在的类型数据{}", tempData.keySet());
		}
		
		return templateData;
	}
	
	/**
	 * @title 分类排序器(中级方法)
	 * @param classifier	分组器【必传】。为数据分组提供依据。	类型为  R
	 * @return
	 * @author: xue.zhang
	 * @date 2019年2月2日上午9:45:33
	 */
	public <R> List<TfwStatisticsModel<R, TechnicalFramework>> handler(Function<TechnicalFramework, R> classifier) {
		return this.handler(classifier, null, R -> R);// key值类型转换器，为原类型;
	}

	/**
	 * @title 分类排序器(中级方法)
	 * @param classifier	分组器【必传】。为数据分组提供依据。	类型为  R
	 * @param keyConverter	排序器【必传】，字段真实的类型 K	
	 * @return
	 * @author: xue.zhang
	 * @param <K>
	 * @date 2019年2月2日上午9:45:33
	 */
	public <R, K> List<TfwStatisticsModel<K, TechnicalFramework>> handler(
			Function<TechnicalFramework, R> classifier, 
			Function<R, K> keyConverter
			) {
		return this.handler(classifier, null, keyConverter);// key值类型转换器，为原类型;
	}

	/**
	 * @title 分类排序器(中级方法)
	 * @param classifier	分组器【必传】。为数据分组提供依据。	类型为  R
	 * @param comparator	排序器【可选】。不传的时候，不排序  	类型为  K
	 * @return
	 * @author: xue.zhang
	 * @date 2019年2月2日上午9:45:33
	 */
	public <R> List<TfwStatisticsModel<R, TechnicalFramework>> handler(
			Function<TechnicalFramework, R> classifier, 
			Comparator<TfwStatisticsModel<R, TechnicalFramework>> comparator) {
		return this.handler(classifier, comparator, R -> R);// key值类型转换器，为原类型
	}
	
	/**
	 * @title 核心分类排序器(当前业务中的最底层方法)
	 * @param classifier	分组器【必传】。为数据分组提供依据。	类型为  R
	 * @param comparator	排序器【可选】。不传的时候，不排序  	类型为  K
	 * @param keyConverter	转换器【必传】，字段真实的类型 K				
	 * @return
	 * @author: xue.zhang
	 * @param <K>
	 * @date 2019年2月2日上午9:45:33
	 */
	public <R, K> List<TfwStatisticsModel<K, TechnicalFramework>> handler(
			Function<TechnicalFramework, R> classifier, 
			Comparator<TfwStatisticsModel<K, TechnicalFramework>> comparator,
			Function<R, K> keyConverter
			) {
		if(classifier == null || keyConverter == null) {
			return Lists.newArrayList();
		}
		
		// 查询全部数据
		List<TechnicalFramework> allTfw = this.technicalFrameworkDao.findAll();
		
		// 按照分组器进行分组
		Map<R, List<TechnicalFramework>> map = allTfw.stream().collect(Collectors.groupingBy(classifier));

		// 将分组后的数据封装为集合
		List<TfwStatisticsModel<K, TechnicalFramework>> result = map
				.keySet()
				.stream()
				.map(groupKey -> new TfwStatisticsModel<K, TechnicalFramework>(keyConverter.apply(groupKey), map.get(groupKey)))
				.collect(Collectors.toList());
		
		if(comparator != null) {
			result.sort(comparator);
		}

		return result;
	}
	
	
	
	
	
}
